using Taste;
using ASTClass;



using System;



public class Parser {
	public const int _EOF = 0;
	public const int _ident = 1;
	public const int _number = 2;
	public const int _string = 3;
	public const int maxT = 32;

	const bool T = true;
	const bool x = false;
	const int minErrDist = 2;
	
	public Scanner scanner;
	public Errors  errors;

	public Token t;    // last recognized token
	public Token la;   // lookahead token
	int errDist = minErrDist;

public AST root;
  
/*--------------------------------------------------------------------------*/


	public Parser(Scanner scanner) {
		this.scanner = scanner;
		errors = new Errors();
	}

	void SynErr (int n) {
		if (errDist >= minErrDist) errors.SynErr(la.line, la.col, n);
		errDist = 0;
	}

	public void SemErr (string msg) {
		if (errDist >= minErrDist) errors.SemErr(t.line, t.col, msg);
		errDist = 0;
	}
	
	void Get () {
		for (;;) {
			t = la;
			la = scanner.Scan();
			if (la.kind <= maxT) { ++errDist; break; }

			la = t;
		}
	}
	
	void Expect (int n) {
		if (la.kind==n) Get(); else { SynErr(n); }
	}
	
	bool StartOf (int s) {
		return set[s, la.kind];
	}
	
	void ExpectWeak (int n, int follow) {
		if (la.kind == n) Get();
		else {
			SynErr(n);
			while (!StartOf(follow)) Get();
		}
	}


	bool WeakSeparator(int n, int syFol, int repFol) {
		int kind = la.kind;
		if (kind == n) {Get(); return true;}
		else if (StartOf(repFol)) {return false;}
		else {
			SynErr(n);
			while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {
				Get();
				kind = la.kind;
			}
			return StartOf(syFol);
		}
	}

	
	void Taste() {
		root = new TasteAST(); 
		Expect(4);
		Ident(root);
		Expect(5);
		while (la.kind == 9 || la.kind == 10 || la.kind == 11) {
			if (la.kind == 9 || la.kind == 10) {
				VarDecl(root);
			} else {
				ProcDecl(root);
			}
		}
		Expect(6);
	}

	void Ident(AST parent) {
		IdentAST ident = new IdentAST (parent);  
		Expect(1);
		ident.Value = t.val;   
	}

	void VarDecl(AST parent) {
		AST varDecl = new VarDeclAST(parent); 
		Type(varDecl);
		Ident(varDecl);
		while (la.kind == 7) {
			Get();
			Ident(varDecl);
		}
		Expect(8);
	}

	void ProcDecl(AST parent) {
		AST procDecl = new ProcDeclAST(parent); 
		Expect(11);
		Ident(procDecl);
		Expect(12);
		Expect(13);
		Expect(5);
		while (StartOf(1)) {
			if (la.kind == 9 || la.kind == 10) {
				VarDecl(procDecl);
			} else {
				Stat(procDecl);
			}
		}
		Expect(6);
	}

	void Type(AST parent) {
		TypeAST type = new TypeAST(parent); 
		if (la.kind == 9) {
			Get();
			type.Value = "int"; 
		} else if (la.kind == 10) {
			Get();
			type.Value = "bool"; 
		} else SynErr(33);
	}

	void Stat(AST parent) {
		AST stat = new StatAST(parent); 
		switch (la.kind) {
		case 1: {
			AST funcOrAssign = new FuncOrAssignAST(stat); 
			Ident(funcOrAssign);
			if (la.kind == 14) {
				Get();
				Expr(funcOrAssign);
				Expect(8);
				funcOrAssign.AddOp (Operator.Assign); 
			} else if (la.kind == 12) {
				Get();
				Expect(13);
				Expect(8);
				funcOrAssign.AddOp (Operator.Func); 
			} else SynErr(34);
			break;
		}
		case 15: {
			Get();
			AST ifStat = new IfAST(stat); 
			Expect(12);
			Expr(ifStat);
			Expect(13);
			Stat(ifStat);
			if (la.kind == 16) {
				Get();
				Stat(ifStat);
			}
			break;
		}
		case 17: {
			Get();
			AST whileStat = new WhileAST(stat); 
			Expect(12);
			Expr(whileStat);
			Expect(13);
			Stat(whileStat);
			break;
		}
		case 18: {
			Get();
			AST read = new ReadAST(stat); 
			       read.AddOp(Operator.NoOp); // To keep read node in the simplified AST
			    
			Ident(read);
			Expect(8);
			break;
		}
		case 19: {
			Get();
			AST write = new WriteAST(stat);
			      write.AddOp(Operator.NoOp); // To keep write node in the simplified AST 
			   
			if (StartOf(2)) {
				Expr(write);
			} else if (la.kind == 3) {
				Get();
				StringAST s = new StringAST(write); 
				     s.Value = t.val.Substring (1, t.val.Length-2); 
			} else SynErr(35);
			Expect(8);
			break;
		}
		case 5: {
			Get();
			AST block = new BlockAST(stat); 
			         block.AddOp(Operator.NoOp); // to keep Block in simplified AST 
			
			while (StartOf(1)) {
				if (StartOf(3)) {
					Stat(block);
				} else {
					VarDecl(block);
				}
			}
			Expect(6);
			break;
		}
		default: SynErr(36); break;
		}
	}

	void Expr(AST parent) {
		RelExpr(parent);
	}

	void RelExpr(AST parent) {
		AST expr = new RelExprAST(parent); 
		AddExpr(expr);
		if (StartOf(4)) {
			RelOp(expr);
			AddExpr(expr);
		}
	}

	void AddExpr(AST parent) {
		AST addExpr = new AddExprAST(parent); 
		MulExpr(addExpr);
		while (la.kind == 20 || la.kind == 21) {
			AddOp(addExpr);
			MulExpr(addExpr);
		}
	}

	void RelOp(AST parent) {
		switch (la.kind) {
		case 26: {
			Get();
			parent.AddOp(Operator.Equal);        
			break;
		}
		case 27: {
			Get();
			parent.AddOp(Operator.NotEqual);     
			break;
		}
		case 28: {
			Get();
			parent.AddOp(Operator.Less);         
			break;
		}
		case 29: {
			Get();
			parent.AddOp(Operator.Greater);      
			break;
		}
		case 30: {
			Get();
			parent.AddOp(Operator.LessEqual);    
			break;
		}
		case 31: {
			Get();
			parent.AddOp(Operator.GreaterEqual); 
			break;
		}
		default: SynErr(37); break;
		}
	}

	void MulExpr(AST parent) {
		AST term = new MulExprAST(parent); 
		Factor(term);
		while (la.kind == 24 || la.kind == 25) {
			MulOp(term);
			Factor(term);
		}
	}

	void AddOp(AST parent) {
		if (la.kind == 20) {
			Get();
			parent.AddOp(Operator.Add);       
		} else if (la.kind == 21) {
			Get();
			parent.AddOp(Operator.Subtract);  
		} else SynErr(38);
	}

	void Factor(AST parent) {
		AST factor = new FactorAST(parent); 
		switch (la.kind) {
		case 1: {
			Ident(factor);
			break;
		}
		case 2: {
			Get();
			NumberAST number = new NumberAST(factor); number.Value = t.val; 
			break;
		}
		case 21: {
			Get();
			factor.AddOp (Operator.Negate); 
			Factor(factor);
			break;
		}
		case 22: {
			Get();
			BoolAST bt = new BoolAST(factor); bt.Value = t.val; 
			break;
		}
		case 23: {
			Get();
			BoolAST bt = new BoolAST(factor); bt.Value = t.val; 
			break;
		}
		case 12: {
			Get();
			Expr(factor);
			Expect(13);
			break;
		}
		default: SynErr(39); break;
		}
	}

	void MulOp(AST parent) {
		if (la.kind == 24) {
			Get();
			parent.AddOp(Operator.Multiply);     
		} else if (la.kind == 25) {
			Get();
			parent.AddOp(Operator.Divide);       
		} else SynErr(40);
	}



	public void Parse() {
		la = new Token();
		la.val = "";		
		Get();
		Taste();

    Expect(0);
	}
	
	static readonly bool[,] set = {
		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,T,x,x, x,T,T,x, x,x,x,T, x,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,T,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,T,T,T, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,T,x,x, x,x,x,x, x,x,x,T, x,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x}

	};
} // end Parser


public class Errors {
	public int count = 0;                                    // number of errors detected
	public System.IO.TextWriter errorStream = Console.Out;   // error messages go to this stream
  public string errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text
  
	public void SynErr (int line, int col, int n) {
		string s;
		switch (n) {
			case 0: s = "EOF expected"; break;
			case 1: s = "ident expected"; break;
			case 2: s = "number expected"; break;
			case 3: s = "string expected"; break;
			case 4: s = "\"program\" expected"; break;
			case 5: s = "\"{\" expected"; break;
			case 6: s = "\"}\" expected"; break;
			case 7: s = "\",\" expected"; break;
			case 8: s = "\";\" expected"; break;
			case 9: s = "\"int\" expected"; break;
			case 10: s = "\"bool\" expected"; break;
			case 11: s = "\"void\" expected"; break;
			case 12: s = "\"(\" expected"; break;
			case 13: s = "\")\" expected"; break;
			case 14: s = "\"=\" expected"; break;
			case 15: s = "\"if\" expected"; break;
			case 16: s = "\"else\" expected"; break;
			case 17: s = "\"while\" expected"; break;
			case 18: s = "\"read\" expected"; break;
			case 19: s = "\"write\" expected"; break;
			case 20: s = "\"+\" expected"; break;
			case 21: s = "\"-\" expected"; break;
			case 22: s = "\"true\" expected"; break;
			case 23: s = "\"false\" expected"; break;
			case 24: s = "\"*\" expected"; break;
			case 25: s = "\"/\" expected"; break;
			case 26: s = "\"==\" expected"; break;
			case 27: s = "\"!=\" expected"; break;
			case 28: s = "\"<\" expected"; break;
			case 29: s = "\">\" expected"; break;
			case 30: s = "\"<=\" expected"; break;
			case 31: s = "\">=\" expected"; break;
			case 32: s = "??? expected"; break;
			case 33: s = "invalid Type"; break;
			case 34: s = "invalid Stat"; break;
			case 35: s = "invalid Stat"; break;
			case 36: s = "invalid Stat"; break;
			case 37: s = "invalid RelOp"; break;
			case 38: s = "invalid AddOp"; break;
			case 39: s = "invalid Factor"; break;
			case 40: s = "invalid MulOp"; break;

			default: s = "error " + n; break;
		}
		errorStream.WriteLine(errMsgFormat, line, col, s);
		count++;
	}

	public void SemErr (int line, int col, string s) {
		errorStream.WriteLine(errMsgFormat, line, col, s);
		count++;
	}
	
	public void SemErr (string s) {
		errorStream.WriteLine(s);
		count++;
	}
	
	public void Warning (int line, int col, string s) {
		errorStream.WriteLine(errMsgFormat, line, col, s);
	}
	
	public void Warning(string s) {
		errorStream.WriteLine(s);
	}
} // Errors


public class FatalError: Exception {
	public FatalError(string m): base(m) {}
}

